package com.atguigu.gulimall.cart.interceptor;

import com.atguigu.common.constant.AuthConstant;
import com.atguigu.common.constant.CartConstant;
import com.atguigu.common.to.MemberVo;
import com.atguigu.gulimall.cart.vo.UserInfoVo;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.UUID;

public class CartInterceptor implements HandlerInterceptor {

    public static ThreadLocal<UserInfoVo> toThreadLocal = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //Filter在Interceptor外层，所以这里拿到的request已经是SpringSession用装饰模式装饰后的request了，拿到的是redis-based Session
        HttpSession session = request.getSession();
        MemberVo memberVo = (MemberVo) session.getAttribute(AuthConstant.LOGIN_USER);
        UserInfoVo userInfoVo = new UserInfoVo();
        if (memberVo != null){
            //已登录，加入userId
            userInfoVo.setUserId(memberVo.getId());
        }

        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length > 0){
            for (Cookie cookie : cookies) {
                if (CartConstant.TMP_USER_KEY_COOKIE_NAME.equals(cookie.getName())){
                    userInfoVo.setUserKey(cookie.getValue());
                    userInfoVo.setHasUserKeyCookie(true);
                    break;
                }
            }
        }

        if (userInfoVo.getHasUserKeyCookie() == null || !userInfoVo.getHasUserKeyCookie()){
            //没有user-key,应该生成一个
            String uuid = UUID.randomUUID().toString();
            userInfoVo.setUserKey(uuid);
        }

        /**
         * 这里其实直接放在request中就可以了，用ThreadLocal复习一下也行
         * 再回顾一下
         *    public void set(T value) {
         *         Thread t = Thread.currentThread();
         *         ThreadLocalMap map = getMap(t);
         *         if (map != null) {
         *             map.set(this, value);
         *         } else {
         *             createMap(t, value);
         *         }
         *     }
         *
         *     ThreadLocalMap getMap(Thread t) {
         *         return t.threadLocals;
         *     }
         *
         *     static class ThreadLocalMap是ThreadLocal中的一个内部类
         *     ThreadLocalMap可以理解为一个map，它的key是ThreadLocal对象，value就是ThreadLocal<T>中的泛型T的对象
         *
         *  这里是先获取当前thread对象，每个线程对象都持有一个ThreadLocalMap对象（threadLocals）
         *  然后再用ThreadLocal<T>对象取出对应的value。
         *
         *  注意，每一个线程都持有自己私有的ThreadLocalMap对象，这决定了ThreadLocal的线程隔离的特性
         *  ThreadLocalMap中ThreadLocal是key，也就是说，可以有多个ThreadLocal作为key存在Map中
         *
         */

        toThreadLocal.set(userInfoVo);
        return true; // 放行
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        UserInfoVo userInfoVo = toThreadLocal.get();
        if (userInfoVo.getHasUserKeyCookie() == null || !userInfoVo.getHasUserKeyCookie()){
            Cookie cookie = new Cookie(CartConstant.TMP_USER_KEY_COOKIE_NAME,userInfoVo.getUserKey());
            cookie.setMaxAge(CartConstant.TMP_USER_KEY_COOKIE_EXPIRE_SECOND);
            response.addCookie(cookie);
        }
    }
}
